import io

import requests
import pyaudio
import wave
import time

from utils.Config import AppConfig

# 配置参数（与服务端配置尽量匹配，这里假设和前面服务端定义的一致）
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
CHUNK = int(60 * 10 / 10 / 1000 * RATE * 2)
RECORD_SECONDS = 5  # 设定录制时长，可以根据实际需求调整
samp_width = 2


def get_audio_data():
    while True:  # 使用无限循环来持续交互
        try:
            # 初始化PyAudio
            audio = pyaudio.PyAudio()
            stream = audio.open(format=FORMAT,
                                channels=CHANNELS,
                                rate=RATE,
                                input=True,
                                frames_per_buffer=CHUNK)

            print("开始录制音频...")
            frames = []
            for _ in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
                data = stream.read(CHUNK)
                frames.append(data)
            print("音频录制完成")

            # 将音频帧数据转换为字节流，模拟文件数据
            audio_bytes = b''.join(frames)
            file_like_object = io.BytesIO(audio_bytes)

            # 设置请求的文件及相关头部信息
            files = {'audio_file': ('recorded_audio.wav', file_like_object, 'audio/wav')}
            url = "http://localhost:9000/voice-ai"
            response = requests.post(url, files=files)
            print(f"接口调用成功，状态码: {response.status_code}")
            if response.status_code == 200:
                # 处理音频数据，这里简单示例保存为本地文件，可根据实际需求调整，比如播放音频等
                with wave.open('Response.wav', 'wb') as f:
                    f.setnchannels(CHANNELS)
                    f.setsampwidth(samp_width)
                    f.setframerate(RATE)
                    print("Audio data is saving to Response.wav")
                    f.writeframes(response.content)
            else:
                print(f"接口调用失败，状态码: {response.status_code}")
        except requests.RequestException as e:
            print(f"网络请求出现问题: {e}，等待一段时间后重试...")
            time.sleep(5)  # 遇到网络问题等待5秒后重试，可调整等待时间
            continue  # 跳过本次循环剩余部分，直接进入下一次循环继续尝试
        except Exception as e:
            print(f"出现其他未知错误: {e}，等待一段时间后重试...")
            time.sleep(5)  # 遇到其他问题也等待5秒后重试
            continue
        finally:
            try:
                stream.stop_stream()
                stream.close()
                audio.terminate()  # 关闭PyAudio
            except Exception as e:
                print(f"关闭音频设备资源时出现错误: {e}")

# 定义音量阈值，用于判断声音是否停止，可根据实际情况调整
VOLUME_THRESHOLD = 1000  # 这里只是示例阈值，需根据实际测试调整合适的值
# 用于记录声音低于阈值的持续时间（秒）
silent_duration = 0

def is_silent(audio_data):
    """
    判断给定的音频数据是否为静音（音量低于阈值且过零率低于阈值），综合使用能量阈值和过零率来判断
    :param audio_data: 音频数据字节流，格式为包含多个音频帧的列表，每个音频帧是固定大小的字节数据
    :return: 如果是静音返回True，否则返回False
    """
    # 计算音频数据的能量（这里简单以平方和作为能量衡量，类似均方根的前期计算）
    energy_sum = 0
    num_samples = 0
    for frame in audio_data:
        int_samples = [int.from_bytes(frame[i:i + 2], 'little', signed=True) for i in range(0, len(frame), 2)]
        energy_sum += sum(sample ** 2 for sample in int_samples)
        num_samples += len(int_samples)
    energy = energy_sum / num_samples if num_samples > 0 else 0

    # 计算音频数据的过零率
    zcr_sum = 0
    prev_sample = None
    for frame in audio_data:
        int_samples = [int.from_bytes(frame[i:i + 2], 'little', signed=True) for i in range(0, len(frame), 2)]
        for sample in int_samples:
            if prev_sample is not None:
                if (prev_sample < 0 and sample >= 0) or (prev_sample >= 0 and sample < 0):
                    zcr_sum += 1
            prev_sample = sample
    zcr = zcr_sum / num_samples if num_samples > 0 else 0

    # 设定能量阈值和过零率阈值，可根据实际情况调整
    energy_threshold = 100
    zcr_threshold = 10
    return energy < energy_threshold and zcr < zcr_threshold

config = AppConfig()
def get_audio_data_by_duration():
    global silent_duration
    while True:  # 使用无限循环来持续交互
        try:
            # 初始化PyAudio
            audio = pyaudio.PyAudio()
            stream = audio.open(format=FORMAT,
                                channels=CHANNELS,
                                rate=RATE,
                                input=True,
                                frames_per_buffer=CHUNK)

            print("开始录制音频...")
            frames = []
            silent_count = 0  # 记录连续静音帧数
            while True:
                data = stream.read(CHUNK)
                frames.append(data)
                if is_silent([data]):
                    silent_count += 1
                    if silent_count >= int(RATE / CHUNK * 2):  # 静音帧数达到对应3秒的帧数，停止录制
                        print("声音停止，结束音频录制")
                        break
                else:
                    silent_count = 0
                    silent_duration = 0
            # # 保存录制的音频数据
            # with wave.open('recorded_audio.wav', 'wb') as f:
            #     f.setnchannels(CHANNELS)
            #     f.setsampwidth(samp_width)
            #     f.setframerate(RATE)
            #     f.writeframes(b''.join(frames))
            #     print("声音停止，结束音频录制")
            print("音频录制完成")

            # 将音频帧数据转换为字节流，模拟文件数据
            audio_bytes = b''.join(frames)
            file_like_object = io.BytesIO(audio_bytes)

            # 设置请求的文件及相关头部信息
            files = {'audio_file': ('recorded_audio.wav', file_like_object, 'audio/wav')}
            url = "http://localhost:9000/voice-ai"
            response = requests.post(url, files=files)
            # print(f"接口调用成功，状态码: {response.status_code},接口返回结果: {response.content}")
            if response.status_code == 200:
                # 处理音频数据，这里简单示例保存为本地文件，可根据实际需求调整，比如播放音频等
                # with wave.open('Response.wav', 'wb') as f:
                #     f.setnchannels(CHANNELS)
                #     f.setsampwidth(samp_width)
                #     f.setframerate(RATE)
                #     print("Audio data is saving to Response.wav")
                #     f.writeframes(response.content)
                # 直接将返回的音频数据播放
                p = pyaudio.PyAudio()
                stream = p.open(format=p.get_format_from_width(config.AUDIO_SAMP_WIDTH),
                                channels=config.AUDIO_CHANNELS,
                                rate=config.AUDIO_RATE_OUT,
                                output=True)
                print("开始播放回复音频...")
                for chunk in response.iter_content(chunk_size=8192):
                    if chunk:
                        # 播放音频流
                        stream.write(chunk)
                stream.stop_stream()
                stream.close()
                p.terminate()
            else:
                print(f"接口调用失败，状态码: {response.status_code}")
        except requests.RequestException as e:
            print(f"网络请求出现问题: {e}，等待一段时间后重试...")
            time.sleep(5)  # 遇到网络问题等待5秒后重试，可调整等待时间
            continue  # 跳过本次循环剩余部分，直接进入下一次循环继续尝试
        except Exception as e:
            print(f"出现其他未知错误: {e}，等待一段时间后重试...")
            time.sleep(5)  # 遇到其他问题也等待5秒后重试
            continue
        finally:
            try:
                stream.stop_stream()
                stream.close()
                audio.terminate()  # 关闭PyAudio
            except Exception as e:
                print(f"关闭音频设备资源时出现错误: {e}")



if __name__ == '__main__':
    get_audio_data_by_duration()